﻿using System;
using System.IO;
using System.Text;
using System.Data;
using System.Linq;
using System.Drawing;
using System.Collections.Generic;
using System.Windows.Forms;
using Syncfusion.XlsIO;
using Syncfusion.Drawing;
using Syncfusion.Windows.Forms;
using Syncfusion.Windows.Forms.Grid.Grouping;
using Syncfusion.Windows.Forms.Grid;
using PMngr.Data;

namespace PMngr.Main
{
    public partial class UnitImporter : BaseControl
    {
        private IRepositoryFactory repositoryFactory;
        private int recordCount;

        public UnitImporter()
        {
            InitializeComponent();
            InitializeGrid();
        }

        public UnitImporter(IRepositoryFactory repositoryFactory)
            : this()
        {
            this.repositoryFactory = repositoryFactory;
        }

        public override void InitializeControls()
        {
            comUnitType.SelectedIndexChanged -= ComUnitTypeSelectedIndexChanged;
            // 单位区域
            InitializeDropDownList();
            // 主管部门
            InitializeComboBox();
            comUnitType.SelectedIndexChanged += ComUnitTypeSelectedIndexChanged;
        }

        private void InitializeDropDownList()
        {
            using (var repository = repositoryFactory.CreateRepository())
            {
                // 单位区域
                var options1 = repository.All<ItemBase>();
                var datasource1 = from o in options1
                                  where o.Type == "UnitType" && o.IsValid
                                  orderby o.Order
                                  select new {o.Code, o.Name};
                var result1 = datasource1.ToList();
                result1.Insert(0, new {Code = DefaultAll.DefaultValue, Name = DefaultAll.DefaultName});
                comUnitType.DataSource = result1;
                comUnitType.DisplayMember = ItemModel.GetPropertyName(u => u.Name);
                comUnitType.ValueMember = ItemModel.GetPropertyName(u => u.Code);
            }
        }

        private void InitializeComboBox()
        {
            using (var repository = repositoryFactory.CreateRepository())
            {
                // 主管部门
                var units = repository.Find<Unit>(u => u.IsValid && u.ParentUnit == null);
                var datasource = from u in units
                                 select new {u.Id, u.Name};
                var result = datasource.ToList();
                result.Insert(0, new {Id = DefaultAll.DefaultValue, Name = DefaultAll.DefaultName});
                comUpUnit.DataSource = result;
                comUpUnit.DisplayMember = UnitModel.GetPropertyName(u => u.Name);
                comUpUnit.ValueMember = UnitModel.GetPropertyName(u => u.Id);
                // settings
                var grid = comUpUnit.ListBox.Grid;
                grid.Cols.DefaultSize = 230;
                grid.HideCols[UnitModel.GetPropertyName(u => u.Id)] = true;
                grid.PrepareViewStyleInfo += GridListPrepareViewStyleInfo;
            }
        }

        private static void GridListPrepareViewStyleInfo(object sender, GridPrepareViewStyleInfoEventArgs e)
        {
            if (e.ColIndex == 2 && e.RowIndex == 0)
            {
                e.Style.Text = Utilities.MajorUnitSelected;
            }
        }

        private void ComUnitTypeSelectedIndexChanged(object sender, EventArgs e)
        {
            var unitType = comUnitType.SelectedValue;
            // 主管部门
            if ((int)unitType == -1)
            {
                InitializeComboBox();
            }
            else
            {
                using (var repository = repositoryFactory.CreateRepository())
                {
                    var units =
                        repository.Find<Unit>(
                            u => u.IsValid && u.ParentUnit == null && u.UnitType.Code == (int) unitType);
                    var datasource = from u in units
                                     select new {u.Id, u.Name};
                    var result = datasource.ToList();
                    result.Insert(0, new {Id = DefaultAll.DefaultValue, Name = DefaultAll.DefaultName});
                    comUpUnit.DataSource = result;
                    comUpUnit.DisplayMember = UnitModel.GetPropertyName(u => u.Name);
                    comUpUnit.ValueMember = UnitModel.GetPropertyName(u => u.Id);
                }
            }
        }
       
        private void InitializeGrid()
        {
            gridList.TableDescriptor.Name = @"单位信息";
            
            gridList.InitializeGridGrouping();
            // caption
            gridList.TopLevelGroupOptions.ShowCaption = true;
            gridList.TopLevelGroupOptions.CaptionText = Utilities.CategoryCaption;
            gridList.TopLevelGroupOptions.ShowAddNewRecordBeforeDetails = false;
        }

        private void BtnFileClick(object sender, EventArgs e)
        {
            if (openFileDialog.ShowDialog() == DialogResult.OK && openFileDialog.CheckPathExists)
            {
                txtFile.Text = openFileDialog.FileName;
                // import profiles
                GetProfiles(txtFile.Text);
                if(recordCount != 0 )
                    btnImport.Enabled = true;
            }           
        }

        private void BtnImportClick(object sender, EventArgs e)
        {
            var file = txtFile.Text;
            if (String.IsNullOrWhiteSpace(file))
            {
                MessageFactory.Show(Utilities.FirstImportFile, MessageBoxIcon.Exclamation);
                return;
            }
            if (String.IsNullOrWhiteSpace(comUpUnit.Text) || comUpUnit.Text == DefaultAll.DefaultName)
            {
                MessageFactory.Show(Utilities.MajorUnitFirstRequired, MessageBoxIcon.Exclamation);
                return;
            }
            try
            {
                using (var repository = repositoryFactory.CreateRepository())
                {
                    var units = new List<Unit>();
                    var filename = Path.GetFileName(file);
                    // save the profile 
                    SaveUnits(repository, units);
                    // 检查单位名称是否已重复：1，已有单位重复；2，导入数据重复
                    var duplicatedUnits = DuplicatedUnitName(repository, units);
                    repository.CommitChanges();
                    btnImport.Enabled = false;

                    if (duplicatedUnits.Any())
                    {
                        var desc1 = GetUnitsFromSystem(duplicatedUnits);
                        var desc2 = GetUnitsFromSelf(duplicatedUnits);
                        var msg = String.Empty;
                        if (!String.IsNullOrWhiteSpace(desc1))
                            msg = String.Format(Utilities.DuplicatedUnit1, desc1);
                        if (!String.IsNullOrWhiteSpace(desc2))
                            msg = msg + "\r\n" + String.Format(Utilities.DuplicatedUnit2, desc2);
                        LogTrace(String.Format(Utilities.DuplicatedUnit, msg), MessageType.Exclamation);
                    }
                    else
                        LogTrace(String.Format(Utilities.ImportPrompt, filename, recordCount));
                }
            }
            catch (Exception ex)
            {
                LogTrace(ex.Message, MessageType.Error);
            }
        }

        private static string GetUnitsFromSystem(IEnumerable<UnitImpl> units)
        {
            return GetUnits(units, UnitType.System);           
        }
        private static string GetUnitsFromSelf(IEnumerable<UnitImpl> units)
        {
            return GetUnits(units, UnitType.Inner);           
        }
        private static string GetUnits(IEnumerable<UnitImpl> units, UnitType type)
        {
            var sb = new StringBuilder();
            foreach (var u in units)
            {
                if (u.Type == type)
                    sb.AppendFormat("{0} \r\n", u.Unit);
            }

            return sb.ToString();
        }

        private IEnumerable<UnitImpl> DuplicatedUnitName(IRepository repository, IEnumerable<Unit> units)
        {
            var existUnits = new List<UnitImpl>();
            // 导入数据重复
            var result = from u in units
                         group u by u.Name
                         into g
                         where g.Count() > 1
                         select g.Key;
            if (result.Any())
                existUnits.AddRange(result.Select(u=> new UnitImpl{Unit = u, Type = UnitType.Inner}));

            // 已有单位重复
            foreach (var unit in units)
            {
                var temp = unit;
                var list = repository.Find<Unit>(u => u.IsValid && u.Name == temp.Name && u.UnitType.Type == "UnitKind");
                if(list.Any())
                    existUnits.Add(new UnitImpl{ Unit = temp.Name, Type = UnitType.System });
            }

            return existUnits;
        }

        private void SaveUnits(IRepository repository, IList<Unit> units)
        {
            var data = gridList.DataSource as DataTable;
            if (data == null) return;
            
            var unitPId = (int)comUpUnit.SelectedValue;
            var parentUnit = repository.Find<Unit>(unitPId);

            foreach (DataRow row in data.Rows)
            {
                var unit = new Unit
                               {
                                   Name = GetString(row, 0),
                                   UnitType = GetUnitInstance(repository, row, 1, "UnitKind"),
                                   Capacity = GetInt(row, 2),
                                   Contact = GetString(row, 4),
                                   ContactTel = GetString(row, 5),
                                   Address = GetString(row, 6),
                                   CreateDate = DateTime.Now,
                                   ParentUnit = parentUnit,
                                   Description = String.Format(Utilities.UnitDescription, FormatDesc(GetString(row, 3)), FormatDesc(GetString(row, 7)))
                               };
                units.Add(unit);
                repository.Add(unit);
            }
        }

        private static string FormatDesc(string data)
        {
            return String.IsNullOrWhiteSpace(data) ? Utilities.Null : data;
        }

        private static string GetString(DataRow row, int index)
        {
            var obj = row[index];
            if (obj == DBNull.Value) return String.Empty;

            var result = obj == null ? String.Empty : obj.ToString();
            var str = result.Replace("\n","");

            return str;
        }
        private static int GetInt(DataRow row, int index)
        {
            object obj = row[index];
            if (obj == DBNull.Value) return 0;
            int result;
            if(int.TryParse(obj.ToString(), out result))
                return result;
            return 0;
        }
        private ItemBase GetUnitInstance(IRepository repository, DataRow row, int index, string type)
        {
            var obj = row[index];
            var item = repository.Find<ItemBase>(i => i.Type == "UnitKind").ToList()[0];
            if (obj == DBNull.Value) return item;

            if (obj != null)
            {
                var name = obj.ToString();
                var items = repository.Find<ItemBase>(i => i.Type == type && i.Name.Contains(name));
                if (items.Any())
                    item = items.ToList()[0];
            }

            return item;
        }

        private void GetProfiles(string file)
        {
            try
            {
                //Step 1 : Instantiate the spreadsheet creation engine.
                var excelEngine = new ExcelEngine();
                //Step 2 : Instantiate the excel application object.
                IApplication application = excelEngine.Excel;
                IWorkbook workbook = application.Workbooks.Open(file);
                //The first worksheet object in the worksheets collection is accessed.
                IWorksheet sheet = workbook.Worksheets[0];
                //Read data from spreadsheet.
                sheet.UsedRangeIncludesFormatting = false;
                int maxRows = sheet.Rows.Count() - 4;
                DataTable data = sheet.ExportDataTable(4, 1, maxRows, 8, ExcelExportDataTableOptions.ColumnNames);
                gridList.DataSource = data;
                recordCount = data.Rows.Count;
                //Close the workbook.
                workbook.Close();
                //No exception will be thrown if there are unsaved workbooks.
                excelEngine.ThrowNotSavedOnDestroy = false;
                excelEngine.Dispose();
            }
            catch
            {
                LogTrace(Utilities.ImportError, MessageType.Exclamation);
                return;
            }
        }
    
        class UnitImpl
        {
            public string Unit { get; set; }
            public UnitType Type { get; set; }
        }

        enum UnitType
        {
            Inner,
            System
        }

    }


}
